﻿using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using SqlSugar;
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using 请求响应加密.Attr;
using 请求响应加密.Common;
using 请求响应加密.ConfigModel;
using 请求响应加密.DAL;
using 请求响应加密.IService;
using 请求响应加密.Models.SqlSugarDemo;
using 请求响应加密.Param;
using 请求响应加密.Tools;
using 请求响应加密.Tools.Config;
using 请求响应加密.Tools.Encrypt;
using 请求响应加密.Tools.Excel;
using 请求响应加密.Tools.Http;
using 请求响应加密.Tools.ID;
using 请求响应加密.Tools.PDF;

namespace 请求响应加密.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ToolsController : ControllerBase
    {
        private ILogger<ToolsController> logger;
        private IConverter converter;
        private IUserService userService;
        private SugarDbContext sugarDbContext;
        private IRepository repository;
        private IMemoryCache memoryCache;

        public ToolsController(IConverter converter, ILogger<ToolsController> logger,IUserService userService,SugarDbContext _sugarDbContext,IRepository _repository,IMemoryCache _memoryCache
            )
        {
            this.converter = converter;
            this.logger = logger;
            this.userService = userService;
            this.sugarDbContext = _sugarDbContext;
            this.repository = _repository;
            this.memoryCache = _memoryCache;
        }

        [Route("HtmlToPDF")]
        [HttpPost]
        public IActionResult HtmlToPDF([FromForm] string contractData, bool base64Str = true)
        {
            string contractContent = string.Empty;
            if (base64Str)
            {
                byte[] body = Convert.FromBase64String(contractData);
                contractContent = Encoding.UTF8.GetString(body);
            }
            else
            {
                contractContent = contractData;
            }

            HtmlToPdfDocument doc = new HtmlToPdfDocument()
            {
                GlobalSettings = {
                    Margins = new MarginSettings(14,10,30,10),
                    ColorMode = ColorMode.Color,
                    Orientation = Orientation.Portrait,
                    PaperSize = PaperKind.A4,
                },
                Objects = {
                    new ObjectSettings() {
                        PagesCount = true,
                        HtmlContent = contractContent,
                        WebSettings = { DefaultEncoding = "utf-8" },
                        HeaderSettings = { FontSize = 12,FontName="微软雅黑", Right = "Page [page] of [toPage]", Line = true, Left="XX省XX市XX县", Spacing = 1.8 },
                    }
                }
            };

            byte[] buff = converter.Convert(doc);
            string timeStr = DateTime.Now.ToString("yyyyMMddffff");
            string path = AppDomain.CurrentDomain.BaseDirectory + $"/CLF{timeStr}.pdf";
            System.IO.File.WriteAllBytes(path, buff);
            return Ok("转换成功");
        }

        [Route("HtmlToPDF2")]
        [HttpPost]
        public ActionResult<OperateResult> HtmlToPDF2([FromForm] string contractData, [FromForm] string filePath, bool base64Str = true)
        {
            Param.OperateResult operateResult = PDFHelper.HtmlToPDF(contractData, base64Str);
            if (!operateResult.State)
                return operateResult;
            byte[]? buff = operateResult.Data as byte[];
            System.IO.File.WriteAllBytes(filePath, buff);
            return new OperateResult("转换成功");
        }

        [Route("Proxy")]
        [HttpGet]
        public async Task<ActionResult<string>> ProxyRequestAsync(string url, bool useProxy = false)
        {
            Dictionary<string, string> headers = new Dictionary<string, string>();
            headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36");
            ProxySetting proxySetting = null;
            if (useProxy)
            {
                proxySetting = new ProxySetting();
                proxySetting.UseProxy = true;
                proxySetting.Protocol = "http";
                proxySetting.Address = "127.0.0.1";
                proxySetting.Port = "10809";
            }

            HttpClient httpClient = HttpHelper.HttpClientSettings(headers, proxySetting);
            HttpResponseMessage resp = await httpClient.GetAsync(url);
            resp.EnsureSuccessStatusCode();

            using (Stream stream = await resp.Content.ReadAsStreamAsync())
            {
                StreamReader sr = new StreamReader(stream);
                return sr.ReadToEnd();
            }
        }

        [Route("GenID")]
        [HttpGet]
        public ActionResult<List<string>> GenerateIDs(int count = 1)
        {
            DriftSnowflakeIdGenerator generator = new DriftSnowflakeIdGenerator(1L,1L);
            List<string> Ids = new List<string>();
            for (int i = 0; i < count; i++)
            {
                Ids.Add($"UID{generator.NextId()}");
            }

            return Ids;
        }


        // 这里如果不显式指定数据来源的话，ASP.NET Core 默认只会从下列位置找参数：对于简单类型（如 string, int）：
        // GET 会从 querystring，
        // POST 会从 route / body（不稳定）
        // 对于 POST application/x-www-form-urlencoded：你需要显式标注[FromForm] 来绑定表单字段
        [Route("GenToken")]
        [HttpPost]
        public ActionResult<string> GenToken([FromForm] string id, [FromForm] string name, [FromForm] string pass)
        {
            User user = new User() { ID = id, Name = name, Password = pass };
            return JwtHelper.GenerateToken(user);
        }

        [Route("ContextTest")]
        [HttpGet]
        public async Task<string> ContextTest()
        {
            await Task.Delay(1000);
            User user = (User)HttpContext.Items["user"];

            user.ID = "UID11100000";
            user = userService.GetUser(user.ID);
            return JsonConvert.SerializeObject(user,Formatting.Indented);
        }

        [Route("CreateModels")]
        [HttpGet]
        public ActionResult<string> CreateModels()
        {
            sugarDbContext.GenerateModels("SqlSugarDemo",
                "D:\\Code\\WebAPI\\请求响应加密\\Models\\SqlSugarDemo\\",
                namesp: "请求响应加密.Models.SqlSugarDemo",
                processLog: msg=> LogHelper.Info(msg));
            return "生成成功";
        }

        [Route("GenExcel")]
        [HttpGet]
        public ActionResult<string> GenExcel(string excelName)
        {
            Random random = new Random();
            string[] layers = new string[] { "管理员", "用户", "访客" };
            List<User> users = new List<User>();

            for (int i = 0; i < 30; i++)
            {
                var user = new User()
                {
                    ID = "UID" + i.ToString().PadLeft(6, '0'),
                    Name = $"User:{i:d2}",
                    Password = "123456",
                    Age = random.Next(0, 120),
                    Address = "河北省唐山市路北区",
                    Layer = layers[random.Next(layers.Length)],
                    State = random.Next(0, 2) == 0 ? "正常" : "冻结"
                };
                users.Add(user);
            }
            ExcelHelper.SaveToFile(users, excelName);
            return "导出excel成功";
        }

        [Route("GenTestData")]
        [HttpGet]
        public ActionResult<string> GenTestData()
        {
            DriftSnowflakeIdGenerator snowFlakeIdGenerator = new DriftSnowflakeIdGenerator(1, 1);
            string[] roleNames = new string[] { "Admin", "User", "Guest" };
            foreach (var name in roleNames)
            {
                DataRole dataRole = new DataRole()
                {
                    RoleID = $"RID{snowFlakeIdGenerator.NextId()}",
                    RoleName = name
                };
                repository.Insert<DataRole>(dataRole);
            }

            string[] perms = new string[] { "Admin:Read","Admin:Write","Admin:Update","Admin:Delete","User:Read","User:Write","Guest:Read" };
            foreach (var perm in perms)
            {
                DataPermission dataPermission = new DataPermission()
                {
                    PermID = $"PM{snowFlakeIdGenerator.NextId()}",
                    PermName = perm
                };
                repository.Insert<DataPermission>(dataPermission);
            }

            return "finish";
        }

        [Route("PermsTest")]
        [HttpGet]
        [Permission("Admin:Read")]
        public ActionResult<string> GetTestData()
        {
            return "用户权限可以访问该接口";
        }

        [Route("GetPublicKey")]
        [HttpGet]
        public ActionResult<string> GetPublicKey()
        {
            return ConfigHelper.Get<string>("RSA", "pubkey");
        }

        [Route("PublicKeyEncrypt")]
        [HttpPost]
        public ActionResult<string> PublicKeyEncrypt([FromForm] string rawText, [FromForm] string pubKey)
        {
            if (string.IsNullOrEmpty(rawText) || string.IsNullOrEmpty(pubKey))
                throw new Exception("传入的加密参数不能为空");
            string encryptedData = EncryptHelper.RSAEncrypt(rawText, pubKey);
            Console.WriteLine(encryptedData);
            return encryptedData;
        }

        [Route("SetCommunityKey")]
        [HttpPost]
        public ActionResult<string> SetCommunityKey([FromForm] string encryptKey)
        {
            string key = EncryptHelper.RSADecrypt(encryptKey, ConfigHelper.Get<string>("RSA", "prkey"));
            bool logined = HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues token);
            if (logined)
            {
                memoryCache.Set(token, key, DateTimeOffset.Now.AddMinutes(60));
                return "设置通信密钥成功";
            }
            else
            {
                return "设置通信密钥失败";
            }
        }

        [Route("AesComm")]
        [HttpGet]
        public ActionResult<string> AesComm(string rawText)
        {
            return $"返回解析数据: {rawText}";
        }


        [Route("DataExport")]
        [HttpGet]
        public ActionResult<string> DataExport(string name)
        {
            if (string.IsNullOrEmpty(name))
                return "名称不能为空";
            try
            {
                List<SqlConnectionInfo> conns = ConfigHelper.GetSection<List<SqlConnectionInfo>>("ConnectionList");
                List<ConnectionConfig> connConfigs = new List<ConnectionConfig>();
                foreach (var conn in conns)
                {
                    connConfigs.Add(new ConnectionConfig()
                    {
                        ConfigId = conn.ConfigId,
                        ConnectionString = conn.ConnectionString,
                        DbType = Enum.Parse<DbType>(conn.DbType),
                        IsAutoCloseConnection = conn.IsAutoCloseConnection,
                        ConfigureExternalServices = new ConfigureExternalServices
                        {
                            //注意:  这儿AOP设置不能少
                            EntityService = (c, p) =>
                            {
                                /***低版本C#写法***/
                                // int?  decimal?这种 isnullable=true,string类型需要特别处理
                                if (p.IsPrimarykey)
                                {
                                    p.IsNullable = false;
                                }
                                else if (c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                                {
                                    p.IsNullable = true;
                                }
                                else if (c.PropertyType == typeof(string))
                                {
                                    if (c.GetCustomAttribute<RequiredAttribute>() == null)
                                        p.IsNullable = true;
                                }
                            }
                        }
                    });
                }

                Type[] types = Assembly.GetExecutingAssembly().GetTypes();
                List<Type> types1 = types.Where(type => type.Namespace == $"请求响应加密.Models.{name}").ToList();

                SqlSugarClient sqlClient1 = new SqlSugarClient(connConfigs);
                sqlClient1.ChangeDatabase(name);


                MethodInfo? sqlMethod = typeof(SqlSugarClient).GetMethod("Queryable",new[]{ typeof(string) });
                string dir = AppDomain.CurrentDomain.BaseDirectory + "ExcelFile";
                string dir1 = dir + $"\\{name}";
                Directory.Delete(dir,true);
                if (!Directory.Exists(dir1)) Directory.CreateDirectory(dir1);

                foreach (var type in types1)
                {
                    SugarTable? tableAttr = type.GetCustomAttribute<SugarTable>();
                    string table = tableAttr.TableName;
                    LogHelper.Info($"正在处理的表: {table}");

                    MethodInfo queryMethod = sqlMethod.MakeGenericMethod(type);
                    var queryableInstance = queryMethod.Invoke(sqlClient1, new object[] { table });
                    var toPageListMethod = queryableInstance.GetType().GetMethod("ToPageList", new[] { typeof(int), typeof(int) });
                    var list = toPageListMethod.Invoke(queryableInstance, new object[] { 1, 20 });

                    Type excelType = typeof(ExcelHelper);
                    Type listType = typeof(List<>).MakeGenericType(type);
                    MethodInfo? method = excelType.GetMethod("SaveToFile");
                    MethodInfo methodInfo = method.MakeGenericMethod(type);

                    string filePath = $"{dir1}\\{table}.xlsx";
                    methodInfo.Invoke(null, new object[] { list,filePath, false });
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return "数据导出成功";
        }
    }
}
